package com.guoyan.blockchain.service.impl;

import com.guoyan.blockchain.common.client.ChannelClient;
import com.guoyan.blockchain.common.exception.FabricException;
import com.guoyan.blockchain.common.response.BaseResponse;
import com.guoyan.blockchain.service.IBaseService;
import com.guoyan.blockchain.service.parent.ParentService;
import org.hyperledger.fabric.sdk.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


/**
 * @author yeym
 */
@Service
public class BaseServiceImpl extends ParentService implements IBaseService {

    @Value("${network.ip}")
    public String networkIp;

    @PostConstruct
    public void t(){
        System.out.println(networkIp);
    }

    @Override
    public boolean createChannel(String channelName) {
        File file = new File("channels/" + channelName + ".ser");
        if (file.exists()){
            return false;
        }
        final String path = "./createChannel.sh";
        try {
            Process process = Runtime.getRuntime().exec(path+" "+channelName,null,new File("../network"));
            process.waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        try {
            file.delete();
            // Create a new channel
            file.createNewFile();
            Orderer orderer = fabricClient.getInstance().newOrderer("orderer.example.com", "grpc://"+networkIp+":7050");
            Peer peer0Org1 = fabricClient.getInstance().newPeer("peer0.org1.example.com", "grpc://"+networkIp+":7051");
            Peer peer1Org1 = fabricClient.getInstance().newPeer("peer1.org1.example.com", "grpc://"+networkIp+":7056");
            Peer peer0Org2 = fabricClient.getInstance().newPeer("peer0.org2.example.com", "grpc://"+networkIp+":8051");
            Peer peer1Org2 = fabricClient.getInstance().newPeer("peer0.org2.example.com", "grpc://"+networkIp+":8056");
            Peer peer0Org3 = fabricClient.getInstance().newPeer("peer1.org3.example.com", "grpc://"+networkIp+":9051");
            Peer peer1Org3 = fabricClient.getInstance().newPeer("peer1.org3.example.com", "grpc://"+networkIp+":9056");
            ChannelConfiguration channelConfiguration = new ChannelConfiguration(new File("../network/config/" + channelName + ".tx"));
            byte[] channelConfigurationSignatures = fabricClient.getInstance().getChannelConfigurationSignature(channelConfiguration, org1Admin);
            Channel myChannel = fabricClient.getInstance().newChannel(channelName, orderer, channelConfiguration, channelConfigurationSignatures);
            myChannel.joinPeer(peer0Org1);
            myChannel.joinPeer(peer1Org1);
            myChannel.addOrderer(orderer);
            myChannel.initialize();
            fabricClient.getInstance().setUserContext(org2Admin);
            myChannel = fabricClient.getInstance().getChannel(channelName);
            myChannel.joinPeer(peer0Org2);
            myChannel.joinPeer(peer1Org2);
            fabricClient.getInstance().setUserContext(org3Admin);
            myChannel = fabricClient.getInstance().getChannel(channelName);
            myChannel.joinPeer(peer0Org3);
            myChannel.joinPeer(peer1Org3);
            myChannel = fabricClient.getInstance().getChannel(channelName);
            myChannel.serializeChannel(file);
            myChannel.getPeers().forEach(x -> logger.info("url ==> {} , name ==> {}", x.getUrl(), x.getName()));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new FabricException("通道创建失败");
        }

    }

    @Override
    public boolean deployChainCode(String chainCodeName, Integer version, String channelName) {
        File file = new File("channels/" + channelName + ".ser");
        boolean flag = true;
        try {
            fabricClient.getInstance().setUserContext(org1Admin);
            Channel channel = fabricClient.getInstance().getChannel(channelName);
            if (channel == null) {
                channel = fabricClient.getInstance().deSerializeChannel(file);
            }
            channel.initialize();
            Peer peer0Org1 = fabricClient.getInstance().newPeer("peer0.org1.example.com", "grpc://"+networkIp+":7051");
            Peer peer1Org1 = fabricClient.getInstance().newPeer("peer1.org1.example.com", "grpc://"+networkIp+":7056");
            Peer peer0Org2 = fabricClient.getInstance().newPeer("peer0.org2.example.com", "grpc://"+networkIp+":8051");
            Peer peer1Org2 = fabricClient.getInstance().newPeer("peer0.org2.example.com", "grpc://"+networkIp+":8056");
            Peer peer0Org3 = fabricClient.getInstance().newPeer("peer1.org3.example.com", "grpc://"+networkIp+":9051");
            Peer peer1Org3 = fabricClient.getInstance().newPeer("peer1.org3.example.com", "grpc://"+networkIp+":9056");
            List<Peer> org1Peers = new ArrayList<>();
            org1Peers.add(peer0Org1);
            org1Peers.add(peer1Org1);
            List<Peer> org2Peers = new ArrayList<>();
            org2Peers.add(peer0Org2);
            org2Peers.add(peer1Org2);
            List<Peer> org3Peers = new ArrayList<>();
            org3Peers.add(peer0Org3);
            org3Peers.add(peer1Org3);
            //安装
            Collection<ProposalResponse> response = fabricClient.deployChainCode(chainCodeName, null, "../network_resources/chaincode", TransactionRequest.Type.JAVA,
                    version.toString(), org1Peers);
            for (ProposalResponse res : response) {
                logger.info("链码安装  url==>{} ,state == >{}", res.getPeer().getUrl(), res.getStatus());
            }
            fabricClient.getInstance().setUserContext(org2Admin);
            //安装
            response = fabricClient.deployChainCode(chainCodeName, null, "../network_resources/chaincode", TransactionRequest.Type.JAVA,
                    version.toString(), org2Peers);
            for (ProposalResponse res : response) {
                logger.info("链码安装  url==>{} ,state == >{}", res.getPeer().getUrl(), res.getStatus());
            }
            fabricClient.getInstance().setUserContext(org3Admin);
            //安装
            response = fabricClient.deployChainCode(chainCodeName, null, "../network_resources/chaincode", TransactionRequest.Type.JAVA,
                    version.toString(), org3Peers);
            for (ProposalResponse res : response) {
                logger.info("链码安装  url==>{} ,state == >{}", res.getPeer().getUrl(), res.getStatus());
            }

            ChannelClient channelClient = new ChannelClient(channel.getName(), channel, fabricClient);
            String[] arguments = {""};
            //激活
            response = channelClient.instantiateChainCode(chainCodeName, version.toString(), channel.getPeers(), TransactionRequest.Type.JAVA.toString(), "init", arguments, null);
            for (ProposalResponse res : response) {
                if (res.getStatus().getStatus() != 200) {
                    flag = false;
                }
                logger.info("链码激活  url==>{} ,state == >{}", res.getPeer().getUrl(), res.getStatus());
            }
            return flag;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public BaseResponse joinNewPeer(String ip, String name, String channelName) {
        try {
            fabricClient.getInstance().setUserContext(org1Admin);
            Channel channel = fabricClient.getInstance().newChannel(channelName);
            Orderer orderer = fabricClient.getInstance().newOrderer("oerderer.example.com", "grpc://localhost:7050");
            channel.addOrderer(orderer);
            channel.initialize();
            Peer peer = fabricClient.getInstance().newPeer(name, "grpc://" + ip + ":7051");
            channel.joinPeer(peer);
            List<Peer> peers = new ArrayList<>();
            peers.add(peer);
            //安装
            Collection<ProposalResponse> response = fabricClient.deployChainCode("fabcar", null, "../network_resources/chaincode", TransactionRequest.Type.JAVA,
                    "1", peers);
            for (ProposalResponse res : response) {
                logger.info("链码安装  url==>{} ,state == >{}", res.getPeer().getUrl(), res.getStatus());
            }
            //激活
            ChannelClient channelClient = new ChannelClient(channel.getName(), channel, fabricClient);
            String[] arguments = {""};
            boolean flag = true;
            response = channelClient.instantiateChainCode("fabcar", "1", peers, TransactionRequest.Type.JAVA.toString(), "init", arguments, null);
            for (ProposalResponse res : response) {
                if (res.getStatus().getStatus() != 200) {
                    flag = false;
                }
                logger.info("链码激活  url==>{} ,state == >{}", res.getPeer().getUrl(), res.getStatus());
            }
            if (!flag) {
                return BaseResponse.error("链码激活失败,请重试");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return BaseResponse.successful;
    }

    @Override
    public Object getPeers() {
        return null;
    }
}
